package com.dz51.core.proxy;  

import java.sql.DatabaseMetaData;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class SlaveTemplateContainer extends AbstractTemplateContainer{
	
	private Logger logger = Logger.getLogger(SlaveTemplateContainer.class);
	
	@Override
	public DataSourceType getDataSourceType() {
		return DataSourceType.SLAVE;
	}

	@Override
	public void changDataSource(HibernateTemplate hibernateTemplate, boolean add) {
		synchronized (SlaveTemplateContainer.class) {
			try {
				if(!add){//移除
					int index = hibernateTemplates.indexOf(hibernateTemplate);
					if(index >= hdaoSize.get() || index == -1){
						logger.info("取消移除---该数据源已经可用池中移除");
						return;
					}
					HibernateTemplate hdao = hibernateTemplates.get(index);
					hibernateTemplates.remove(index);//先移除
					hibernateTemplates.add(hibernateTemplates.size(), hdao);//添加到末尾
					hdaoSize.decrementAndGet();
					String subject = "Mysql数据库 hibernate salve 错误次数太多，被移除";
					String content = "Mysql数据库 hibernate salve 错误次数太多，被移除。 当前salve容器还包含 " + hdaoSize.get() + " 个hibernateTemplate有效数据源";
					//content += extractDBInfo(hdao);
					sendWarnNotice(subject, content);
				}else{//添加
					int index = hibernateTemplates.indexOf(hibernateTemplate);
					HibernateTemplate hdao = hibernateTemplates.get(index);
					if(index != -1 && index < hdaoSize.get()){
						logger.info("取消添加---该数据源已经添加到可用池中");
						return;
					}
					if(index != -1){
						hibernateTemplates.remove(index);
					}
					hibernateTemplates.add(0, hdao);//添加到队首
					hdaoSize.incrementAndGet();
					String subject = "Mysql数据库 salve 检测正常，被添加回数据源容器";
					String content = "Mysql数据库 salve 检测正常，被添加回数据源容器。 当前salve容器还包含  " + hdaoSize.get() + " 个hibernateTemplate有效数据源";
					//content += extractDBInfo(jdao);
					sendWarnNotice(subject, content);
				}
				logger.info("slave hibernate 切换数据源");
			} catch (Exception e) {
				logger.error("slave切换数据源发生异常",e);
				String msg = e.getMessage();
				sendWarnNotice("slave切换数据源发生异常", msg);
			}
		}
	}
	
	@Override
	public void changDataSource(JdbcTemplate jdao, boolean add) {
		//TODO 更改数据源 供check调用
		// 只要把由问题的数据源加入或移除就可以了
		synchronized (SlaveTemplateContainer.class) {
			try {
				if(!add){//移除
					int index = jdbcTemplates.indexOf(jdao);
					if(index >= jdaoSize.get() || index == -1){
						logger.info("取消移除---该数据源已经可用池中移除");
						return;
					}
					
					jdbcTemplates.remove(index);
					jdbcTemplates.add(jdbcTemplates.size(), jdao);
					jdaoSize.decrementAndGet();
					String subject = "Mysql数据库 salve 错误次数太多，被移除";
					String content = "Mysql数据库 salve 错误次数太多，被移除。 当前salve容器还包含 " + jdaoSize.get() + " 个jdbcTemplate有效数据源";
					content += extractDBInfo(jdao);
					sendWarnNotice(subject, content);
				}else{//添加
					int index = jdbcTemplates.indexOf(jdao);
					if(index != -1 && index < jdaoSize.get()){
						logger.info("取消添加---该数据源已经添加到可用池中");
						return;
					}
					if(index != -1){
						jdbcTemplates.remove(index);
					}
					jdbcTemplates.add(0, jdao);//添加到队首
					jdaoSize.incrementAndGet();
					String subject = "Mysql数据库 salve 检测正常，被添加回数据源容器";
					String content = "Mysql数据库 salve 检测正常，被添加回数据源容器。 当前salve容器还包含 " + jdaoSize.get() + " 个jdbcTemplate有效数据源";
					content += extractDBInfo(jdao);
					sendWarnNotice(subject, content);
				}
				logger.info("slave jdbctemplate 切换数据源");
			} catch (Exception e) {
				logger.error("slave切换数据源发生异常",e);
				String msg = e.getMessage();
				sendWarnNotice("slave切换数据源发生异常", msg);
			}
		}
	}

	@Override
	public int hash(TemplateType templateType) {
		if(TemplateType.HibernageTemplate.equals(templateType)){
			Random r = new Random();
			int next = r.nextInt(hdaoSize.get());
			int result = next % hdaoSize.get();
			//logger.info("salve采用数据源" + result);
			return result;
		}else if(TemplateType.JdbcTemplate.equals(templateType)){
			Random r = new Random();
			int next = r.nextInt(jdaoSize.get());
			int result = next % jdaoSize.get();
			//logger.info("salve采用数据源" + result);
			return result;
		}else
			return -1;
	}

	@Override
	public void check() {
		// TODO slave 的检测程序
		logger.info("启动slave检测程序");
		for (final JdbcTemplate jdao : jdbcTemplates) {
			threadPoolExecutor.execute(new Runnable(){
				@Override
				public void run() {
					checkSlave(jdao);
				}
			});
		}
		
		for (final HibernateTemplate hdao : hibernateTemplates) {
			threadPoolExecutor.execute(new Runnable(){
				@Override
				public void run() {
					checkSlave(hdao);
				}
			});
		}
	}
	
	/**检测JdbcTemplate slave状态**/
	private void checkSlave(JdbcTemplate jdao){
		int loopErrors = errorTimes;
		int loopSuccess = successTimes;
		while(true){
			boolean success = true;
			try {
				success = checkSlaveStatusOnce(jdao);
			} catch (Exception e1) {
				e1.printStackTrace();
				success = false;
			}
			if(success){
				loopSuccess --;
			}else{
				loopErrors --;
				loopSuccess = successTimes;
			}
			
			if(loopErrors <= 0){
				logger.info("slave检测" + errorTimes + "次错误，开始移除数据源");
				changDataSource(jdao, false);//移除
				loopErrors = errorTimes;
				loopSuccess = successTimes;
			}
			if(loopSuccess <= 0){
				logger.info("slave检测" + successTimes + "次正常，开始添加数据源");
				changDataSource(jdao, true);//添加
				loopSuccess = successTimes;
				loopErrors = errorTimes;
			}
			//休眠一秒
			try {
				Thread.sleep(checkInterval);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**检测HibernateTemplate slave状态**/
	private void checkSlave(HibernateTemplate hdao){
		int loopErrors = errorTimes;
		int loopSuccess = successTimes;
		while(true){
			boolean success = true;
			try {
				success = checkSlaveStatusOnce(hdao);
			} catch (Exception e1) {
				e1.printStackTrace();
				success = false;
			}
			
			if(success){
				loopSuccess --;
			}else{
				loopErrors --;
				loopSuccess = successTimes;
			}
			
			if(loopErrors <= 0){
				logger.info("slave检测" + errorTimes + "次错误，开始移除数据源");
				changDataSource(hdao, false);//移除
				loopErrors = errorTimes;
				loopSuccess = successTimes;
			}
			if(loopSuccess <= 0){
				logger.info("slave检测" + successTimes + "次正常，开始添加数据源");
				changDataSource(hdao, true);//添加
				loopSuccess = successTimes;
				loopErrors = errorTimes;
			}
			//休眠一秒
			try {
				Thread.sleep(checkInterval);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public boolean init() throws Exception {
		logger.info("[ Slave 容器初始化开始 ]");
		boolean success = super.init(false);
//		size.set(jdbcTemplates.size());
		logger.info("Slave 初始化了  " + hibernateTemplates.size() + " 个hibernateTemplates数据源");
		logger.info("Slave 初始化了  " + jdbcTemplates.size() + " 个jdbcTemplates数据源");
		logger.info("[ Slave 容器初始化完毕 ]");
		return success;
	}
	
	/**更改master数据源**/
	public boolean changeMaster(JdbcTemplate jdbcTemplate){
		synchronized (SlaveTemplateContainer.class) {
			DatabaseMetaData metaData = extractDBMetaData(jdbcTemplate);
			String dbUrl = extractDBUrl(metaData);
			String regx = "jdbc:mysql://(.*):(\\d+)/(.*)";
			Pattern p = Pattern.compile(regx);
			Matcher m = p.matcher(dbUrl);
			String host = "";
			String port = "";
			String dbName = "";
			if(m.find()){
				host = m.group(1);
				port = m.group(2);
				dbName = m.group(3);
				int index = -1;
				if((index = dbName.indexOf("?")) > 0){
					dbName = dbName.substring(0, index);
				}
			}
			String user = extractDBUser(metaData);
			if(StringUtils.isNotBlank(user)){
				int index = -1;
				if((index = user.indexOf("@")) > 0){
					user = user.substring(0, index);
				}
			}
			ComboPooledDataSource dataSource = (ComboPooledDataSource)extractDataSource(jdbcTemplate);
			String password = "";
			if(dataSource != null){
				password = dataSource.getPassword();
//				Field f = .getDeclaredField("properties");
//				dataSource.getClass()
//				f.setAccessible(true);
//				f.get();
			}
			logger.info("host:" + host + ", port:" + port + ", dbname:" + dbName + ", user:" + user + ", password:" + password);
			if(StringUtils.isBlank(host) || StringUtils.isBlank(port) || StringUtils.isBlank(user) || StringUtils.isBlank(password)){
				return false;
			}
			
			for (JdbcTemplate jdao : jdbcTemplates) {
				logger.info("slave stop");
				logger.info("change master to master_host=?, master_port=?, master_user=?, master_password=?");
				logger.info("slave start");
//				jdao.update("slave stop");
//				jdao.update("change master to master_host=?, master_port=?, master_user=?, master_password=?", new Object[]{host, port, user, "lagou!@#rw"});
//				jdao.update("slave start");
			}
		}
		return true;
	}
	
	public static void main(String[] args) {
		String s = "jdbc:mysql://101.69.180.46:3307/lagou_online?end=???";
		String regx = "jdbc:mysql://(.*):(\\d+)/(.*)";
		Pattern p = Pattern.compile(regx);
		Matcher m = p.matcher(s);
    	if(m.find()) {
    		System.out.println(m.groupCount());
    		for (int i = 0; i < m.groupCount() + 1; i++) {
    			System.out.println(m.group(i));
			}
    		String a = m.group(3);
    		int index = a.indexOf("?");
    		System.out.println(a.substring(0, index));
    	}
	}

	/** {
	 * Slave_IO_State=Waiting for master to send event, 
	 * Master_Host=10.4.2.232, 
	 * Master_User=root, 
	 * Master_Port=3307, 
	 * Connect_Retry=60, 
	 * Master_Log_File=bin.000008, 
	 * Read_Master_Log_Pos=760451, 
	 * Relay_Log_File=10-4-6-116-relay-bin.000086, 
	 * Relay_Log_Pos=760591, 
	 * Relay_Master_Log_File=bin.000008, 
	 * Slave_IO_Running=Yes, 
	 * Slave_SQL_Running=Yes, 
	 * Replicate_Do_DB=, 
	 * Replicate_Ignore_DB=, 
	 * Replicate_Do_Table=, 
	 * Replicate_Ignore_Table=, 
	 * Replicate_Wild_Do_Table=, 
	 * Replicate_Wild_Ignore_Table=, 
	 * Last_Errno=0, Last_Error=, 
	 * Skip_Counter=0, 
	 * Exec_Master_Log_Pos=760451, 
	 * Relay_Log_Space=760892, 
	 * Until_Condition=None, 
	 * Until_Log_File=, 
	 * Until_Log_Pos=0, 
	 * Master_SSL_Allowed=No, 
	 * Master_SSL_CA_File=, 
	 * Master_SSL_CA_Path=, 
	 * Master_SSL_Cert=, 
	 * Master_SSL_Cipher=, 
	 * Master_SSL_Key=, 
	 * Seconds_Behind_Master=0, 
	 * Master_SSL_Verify_Server_Cert=No, 
	 * Last_IO_Errno=0, 
	 * Last_IO_Error=, 
	 * Last_SQL_Errno=0, 
	 * Last_SQL_Error=, 
	 * Replicate_Ignore_Server_Ids=, 
	 * Master_Server_Id=463307}
	 */
	
}
